﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FANN;
using System.IO.Compression;

using System.IO;
using FANN.Net;

namespace ConsoleSQL
{
    public class Thrain
    {
        FANN.Net.NeuralNet _net;
        DataClasses1DataContext _data;
        public Work _work;
        private TrainingData _threinData;
        string _param;
        int _step;
        int _end;
        int _saveStep;

        public Thrain(Work work)
        {

            _work = work;
            _data = new DataClasses1DataContext();

            var temp = _data.Temp.Where(t => t.idWork == _work.id);

            var set = work.param.Split(';');
            _end = Convert.ToInt32(set[4]);
            _saveStep = Convert.ToInt32(set[5]);

            if (temp.Count() > 0)
            {
                temp.OrderBy(t => t.stap);
                var last = temp.ToList()[temp.Count() - 1];
                _step = last.stap;
                var file = Path.GetTempFileName();
                var dir = Path.GetRandomFileName();
                File.WriteAllBytes(file, last.data.ToArray());
                ZipFile.ExtractToDirectory(file, dir);
                _net = new FANN.Net.NeuralNet();
                _net.CreateFromFile(dir + "\\ann.ann");
                File.Delete(file);
                Directory.Delete(dir, true);
            }
            else
            {
                _net = new NeuralNet();
                var ls = set[3].Split('.');
                var laers = new uint[ls.Length];
                for (var i = 0; i < ls.Length; i++)
                    laers[i] = Convert.ToUInt16(ls[i]);
                _net.CreateStandardArray(laers);
                _net.SetActivationFunctionHidden(
                    (ActivationFunction)Enum.Parse(typeof(ActivationFunction), set[1], true));
                _net.SetActivationFunctionOutput(
                    (ActivationFunction)Enum.Parse(typeof(ActivationFunction), set[2], true));
                _net.SetTrainingAlgorithm(
                    (TrainingAlgorithm)Enum.Parse(typeof(TrainingAlgorithm), set[0], true));
                _net.SetActivationSteepnessHidden(0.5);
                _net.SetActivationSteepnessOutput(0.5);
                _net.SetBitFailLimit(0.035);
                _net.SetLearningMomentum(0);
                _net.SetLearningRate(0.7f);
                _net.SetTrainErrorFunction(ErrorFunction.Linear);
                _net.SetTrainStopFunction(StopFunction.MSE);
                _step = 0;
            }



            var f = Path.GetTempFileName();
            var d = Path.GetRandomFileName();
            File.WriteAllBytes(f, work.DataSet.data.ToArray());
            ZipFile.ExtractToDirectory(f, d);
            _threinData = new TrainingData();
            _threinData.ReadTrainFromFile(d + "\\dat.dat");

            File.Delete(f);
            Directory.Delete(d, true);



        }

        public void Start()
        {
            while (_step <= _end)
            {
                _step++;
                var v = _net.TrainEpoch(_threinData);

                if (_step % _saveStep == 0)
                {
                    var dir = Path.GetRandomFileName();
                    Directory.CreateDirectory(dir);
                    _net.Save(dir + "\\ann.ann");
                    ZipFile.CreateFromDirectory(dir, dir + ".zip");
                    Directory.Delete(dir, true);
                    Temp t = new Temp()
                    {
                        data = File.ReadAllBytes(dir + ".zip"),
                        idWork = _work.id,
                        stap = _step,
                        dateTime = DateTime.Now,
                        test = v.ToString()

                    };
                    File.Delete(dir + ".zip");
                    try
                    {
                        _data.SubmitChanges();
                        _data.Temp.InsertOnSubmit(t);
                        _data.SubmitChanges();
                        Console.WriteLine(_work.name + " " + _step + " =" + v);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    if (_work.state != 1)
                        break;

                }

            }
            _data.Work.Where(t => t.id == _work.id).ToList()[0].state = 2;


            _data.SubmitChanges();

        }



    }
}
